package com.yyfax.account.service;

import com.jaws.core.common.log.Log;
import com.jaws.core.common.util.DateUtil;
import com.yyfax.account.common.annotation.AccountTradeAnno;
import com.yyfax.account.common.enums.TableNameEnum;
import com.yyfax.account.common.enums.TableSequenceEnum;
import com.yyfax.account.common.enums.TradeTypeEnum;
import com.yyfax.account.common.exception.AccountExceptionCode;
import com.yyfax.account.common.util.CommonIdUtils;
import com.yyfax.account.common.util.TableSegmentUtils;
import com.yyfax.account.dao.AccountFlowDao;
import com.yyfax.account.dao.AccountFrozenDao;
import com.yyfax.account.dao.AccountInfoDao;
import com.yyfax.account.domain.AccountFlow;
import com.yyfax.account.domain.AccountFrozen;
import com.yyfax.account.domain.AccountInfo;
import com.yyfax.account.vo.BaseTradeReq;
import com.yyfax.account.vo.FrozenReq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * 账户冻结服务
 * 
 * @author maojian
 * @date 2017-11-02 11:17:13
 * @since v1.0.0
 */
@AccountTradeAnno(TradeTypeEnum.FROZEN)
@Service
public class FrozenServiceImpl extends BaseTradeService<FrozenReq> {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource
	private AccountInfoDao accountInfoDao;

	@Resource
	private AccountFrozenDao accountFrozenDao;

	@Resource
	private AccountFlowDao accountFlowDao;

	@Resource
	private CommonIdUtils commonIdUtils;

	@Override
	@Transactional
	public void doTrade(FrozenReq req, Boolean isBatch) {
		final String OP = "FrozenServiceImpl.doTrade";
		logger.info(Log.op(OP).msg("账户冻结开始").kv("req", req).toString());

		// 1.业务检查
		if (!isBatch) {
			this.checkBusiness(req);
		}

		// 2.保存冻结订单
		String segment = TableSegmentUtils.getTableSegment(TableNameEnum.ACCOUNT_FROZEN, req.getUserId());
		boolean duplicateKeyFlag = false; // 唯一约束冲突标识位
		AccountFrozen accountFrozen = buildAccountFrozen(req);
		try {
			accountFrozenDao.insert(accountFrozen, segment);
		} catch (DuplicateKeyException e) {
			logger.info(Log.op(OP).msg("唯一约束冲突").kv("outTradeNo", req.getTradeNo()).kv("tradeNo", accountFrozen.getTradeNo()).toString(), e);
			duplicateKeyFlag = true;
		}

		// out_trade_no唯一约束冲突，trade_no唯一约束冲突
		if (duplicateKeyFlag) {
			// super.checkFrozenDuplicateKeyCause(accountFrozen, accountFrozenDao, segment);
			AccountFrozen exsitsOrder = accountFrozenDao.queryOrderByOutTradeNo(req.getTradeNo(), segment);
			if (exsitsOrder == null) {
				throw AccountExceptionCode.SYS_ERROR.exp();
			}
			return;
		}

		// 3.驱动往来账户变更
		int result = accountInfoDao.updateFrozen(req.getUserId(), req.getAccountNo(), req.getAmount());
		if (result != 1) {
			throw AccountExceptionCode.AMOUNT_NOT_ENOUGH.exp(req.getTradeNo(), req.getUserId(), req.getAmount());
		}

		// 4.生成账户流水
		if (!CollectionUtils.isEmpty(req.getFlowDataLs())) {
			List<AccountFlow> accountFlows = buildAccountFlow(req);
			for (AccountFlow accountFlow : accountFlows) {
				accountFlowDao.insert(accountFlow, segment);
			}
		}

		logger.info(Log.op(OP).msg("账户冻结结束").kv("req", req).toString());

	}

	/**
	 * 业务校验
	 *
	 * @author maojian
	 * @date 2017-05-27 17:00:18
	 * @since v1.0.0
	 * @param req
	 */
	@Override
	public void checkBusiness(FrozenReq req) {
		AccountInfo account = accountInfoDao.queryAccountInfoByUser(req.getUserId());

		// 验证账户是否存在，userId 与 accountNo 是否对应
		if (account == null || !account.getAccountNo().equals(req.getAccountNo())) {
			throw AccountExceptionCode.ACCOUNT_NOT_EXSITS.exp(req.getAccountNo());
		}

		if (req.getAmount() <= 0) {// 金额不能小于0
			throw AccountExceptionCode.FROZEN_AMOUNT_NEGATIVE.exp(req.getAmount(), req.getTradeNo(), req.getUserId());
		}
	}

	/**
	 * 业务校验
	 * 
	 * @author maojian
	 * @date 2017-05-27 17:00:18
	 * @since v1.0.0
	 * @param req
	 */
	@Override
	public void batchCheckBusiness(FrozenReq req, AccountInfo account) {
		final String OP = "CurrentFrozenServiceImpl.batchCheckBusiness";

		if (account == null || !account.getAccountNo().equals(req.getAccountNo())) {
			logger.error(Log.op(OP).msg("账户不存在").kv("tradeNo", req.getTradeNo()).kv("accountNo", req.getAccountNo()).toString());
			throw AccountExceptionCode.ACCOUNT_NOT_EXSITS.exp(req.getAccountNo());
		}

		if (req.getAmount() <= 0) {
			logger.error(Log.op(OP).msg("冻结金额必须大于0").kv("tradeNo", req.getTradeNo()).kv("amount", req.getAmount()).toString());
			throw AccountExceptionCode.FROZEN_AMOUNT_NEGATIVE.exp(req.getAmount(), req.getTradeNo());
		}
	}

	/**
	 * frozen req转PO
	 * 
	 * @author maojian
	 * @date 2017-05-24 11:08:41
	 * @since v1.0.0
	 * @param req
	 * @return
	 */
	private AccountFrozen buildAccountFrozen(BaseTradeReq req) {
		AccountFrozen po = new AccountFrozen();
		po.setTradeNo(commonIdUtils.generateId(TableSequenceEnum.ACCOUNT_FROZEN));
		po.setOutTradeNo(req.getTradeNo());
		po.setOutBusinessNo(req.getBusinessNo());
		po.setUserId(req.getUserId());
		po.setAccountNo(req.getAccountNo());
		po.setAmount(req.getAmount());
		po.setTradeTime(req.getTradeTime());
		po.setTradeType(req.getTradeType().getCode());
		po.setRemark(req.getRemark());
		po.setCreateTime(DateUtil.getCurrentDateTime());
		po.setUpdateTime(po.getCreateTime());
		po.setSource(req.getSource().getCode());
		po.setRemark(req.getRemark());
		return po;

	}

}
